package com.roobo.hardware;

import com.roobo.common.utils.Utils;
import android.hardware.roobo.ILedControlService;
import android.os.IBinder;

import android.os.RemoteException;
//import android.os.ServiceManager;
import android.util.Log;

import java.io.IOException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
/*
 * Created by weidu on 16-11-10.
 */

public class LedCtrlManager {
    private static final String TAG = "LedCtrlManager";

    public static final int LED_ID_LEFT_BASE = 0;
    public static final int LED_ID_RIGHT_BASE = 16;

    public static final int LED_ANI_ID_STOP = 0;    // 停止当前动画
    public static final int LED_ANI_ID_BREATH = 1;  // 呼吸灯动画
    public static final int LED_ANI_ID_LOOP = 2;    // 跑马灯动画
    public static final int LED_ANI_ID_LOOP_CNT = 3; // 跑马灯动画，可以设置圈数.

    public static final int BLN_LEFT_MASK = 1;
    public static final int BLN_RIGHT_MASK =2;

    public static final int BLN_ALL_MASK = (BLN_LEFT_MASK | BLN_RIGHT_MASK);

    private static LedCtrlManager sInstance = null;
    private ILedControlService mService = null;

    private static boolean mServerDied = false;

    public class LedCtrlInfo {
        public int ledId;
        public int brightLess;
        public int delay;

        public LedCtrlInfo(int id, int bright, int delayMs) {
            ledId = id;
            brightLess = bright;
            delay = delayMs;
        }

        public void set(int bright, int delayMs) {
            brightLess = bright;
            delay = delayMs;
        }
    }

    private LedCtrlManager() {
        //IBinder binder = ServiceManager.getService("ledCtrlService");
        IBinder binder = Utils.getSystemServiceReflect("ledCtrlService");
        if (binder == null) {
            throw new UnsupportedOperationException("could not retrieve ledCtrl service");
        }
        mService = ILedControlService.Stub.asInterface(binder);
    }

    public static synchronized LedCtrlManager getInstance() {
        if (sInstance == null) {
            sInstance = new LedCtrlManager();
        }
        return sInstance;
    }

    /*
     * 设置某颗灯的亮度，
     * ledNum: 灯号
     * 左边的LED, ledNum = LED_ID_LEFT_BASE + id;
     * 右边的LED, ledNum = LED_ID_RIGHT_BASE + id;
     * id = 0 .. getMaxLedNum.left, 0 .. getMaxLedNum.right
     * brightness： 亮度值 ， 0..255
     * delay： 要设置的灯的亮的时长,毫秒
     * 0: 表示一直亮。
     */
    public void setLedLight(int ledNum, int brightness, long mDelay) {
        Log.d(TAG, "setLedLight:ledNum=" + ledNum + ",brightness=" + brightness
                + ",mDelay=" + mDelay);
        try {
            mService.setLedLight(ledNum, brightness, mDelay);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in setLedLight", e);
            mServerDied = true;
        }
    }

    /*
     * this is the service support function.
     */
    private void setLedBatInternal(int[] ctrl_values, int led_nums, boolean left) {
        int ledMask = 0;
        if (left) {
            ledMask |= BLN_LEFT_MASK;  // bit 0: left leds
        } else {
            ledMask |= BLN_RIGHT_MASK;  // bit 1: right leds.
        }
        try {
            mService.setLedLightsBat(ctrl_values, led_nums, ledMask);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in setLedLight", e);
            mServerDied = true;
        }
    }

    private int[] gotLedCtrlValues(LedCtrlInfo[] ctrls, int lednums) {
        int total_len = lednums * 3;
        int[] ctrl_values = new int[total_len];
        for (int i = 0; i < lednums; i++) {
            ctrl_values[i * 3] = ctrls[i].ledId;
            ctrl_values[i * 3 + 1] = ctrls[i].brightLess;
            ctrl_values[i * 3 + 2] = ctrls[i].delay;
        }
        return ctrl_values;
    }

    /*
     * set all left leds light at bat(one time)
     * @param ctrls array of LedCtrlInfo,each item sets one led.
     *              brightLess = -1 means don't change the old value.
     *              brightLess = 0 means turn off.
     */
    public void setLeftLed(LedCtrlInfo[] ctrls) {
        if (mServerDied) {
            return;
        }
        int lednums = Math.min(getMaxLedNum(1),ctrls.length);
        int[] ctrl_values = gotLedCtrlValues(ctrls, lednums);
        setLedBatInternal(ctrl_values, ctrls.length, true);
    }

    /*
     * set all right leds light at bat(one time)
     * @param ctrls array of LedCtrlInfo,each item sets one led.
     *              brightLess = -1 means don't change the old value.
     *              brightLess = 0 means turn off.
     */
    public void setRightLed(LedCtrlInfo[] ctrls) {
        if (mServerDied) {
            return;
        }
        int lednums = Math.min(getMaxLedNum(2),ctrls.length);
        int[] ctrl_values = gotLedCtrlValues(ctrls, lednums);
        setLedBatInternal(ctrl_values, ctrls.length, false);
    }

    /*
     * 获得最大灯的数量
     * the servers return numLeft at high 16bit,numRight at low 16bit.
     * left_right_all: 0 -- got left+right led number.
     * 1 -- got left led number
     * 2 -- got right led number
     */
    public static final int LED_NUM_ALL = 0;
    public static final int LED_NUM_LEFT = 1;
    public static final int LED_NUM_RIGHT = 2;

    private int mLeftMaxLeds = 0;
    private int mRightMaxLeds = 0;

    public int getMaxLedNum(int left_right_all) {
        int num;
        int numLeft;
        if (mLeftMaxLeds == 0) {
            try {
                num = mService.getMaxLedNum();
            } catch (RemoteException e) {
                Log.e(TAG, "RemoteException in getMaxLedNum", e);
                num = 0;
            }
            numLeft = (num >> 16);
            num &= 0XFFFF;
            mLeftMaxLeds = numLeft;
            mRightMaxLeds = num;
        } else {
            numLeft = mLeftMaxLeds;
            num = mRightMaxLeds;
        }
        if (left_right_all == LED_NUM_LEFT) {
            return numLeft;
        } else if (left_right_all == LED_NUM_RIGHT) {
            return num;
        }
        return num + numLeft;
    }

    /*
     * 获得灯支持的最大亮度
     * hardware brightness: 0--255 共256 级。
     * 这个值返回的是 动画状态下 ， LED 的最大和最小亮度。
     */
    public int getMaxLedBrightness(int ledNum) {
        try {
            return mService.getMaxLedBrightness(ledNum);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in getMaxLedBrightness", e);
            return  0;
        }
    }

    /*
     * 获得灯支持的最小亮度
     */
    public int getMinLedBrightness(int ledNum) {
        int brightness;
        try {
            brightness = mService.getMinLedBrightness(ledNum);
            Log.e(TAG, "getMinLedBrightness:"+ brightness);
            return brightness;
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in getMinLedBrightness", e);
            return 0;
        }
    }

    /*
     * 获得某颗灯当前的亮度
     * ledNum: 参数和 setLedLight 一样。
     */
    public int getLedLight(int ledNum) {
        try {
            return mService.getLedLight(ledNum);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in getLedLight", e);
            return 0;
        }
    }

    /*
     * 展现制定动画
     * id:动画id :
     * LED_ANI_ID_XXX.
     * 对于 LED_ANI_ID_STOP 来说，mdelay,loops 无作用。
     * mDelay:
     * 动画每帧变化之间的时长，可以控制动画的速度。
     * ledMask:
     * BIT0: 1 -- 启动左边 LED 动画
     * BIT1： 1 -- 启动右边 LED 动画
     * loops:
     * 只对 LED_ANI_ID_LOOP_CNT 有效，表示跑马灯转动的圈数。
     */
    public void startAnimation(int id, long mDelay, int ledMask, int loops) {
        Log.d(TAG, "startAnimation:id=" + id + ",mDelay=" + mDelay);
        try {
            mService.startAnimation(id, mDelay, ledMask, loops);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in startAnimation", e);
        }
    }

    /*
     * 停止当前所有电话，左边和右边的。
     * 如果需要单独控制 某一边的动画停止，可以通过
     * startAnimation , id 传 LED_ANI_ID_STOP 来停止。
     */
    public void stopAnimation() {
        Log.d(TAG, "stopAnimation!!");
        try {
            mService.stopAnimation();
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in stopAnimation", e);
        }
    }

    /*
     * 配置 LED 的属性。
     * level ：
     * 0--3 表示 LED电流的大小，值越大，电流越大，灯就越亮。
     * maxBrightness,minBrightness:
     * 控制 LED 动画的 最大亮度和最小亮度。
     * setLedLight 的亮度不受这两个控制，setLedLight 的亮度范围是 0..255.
     * stepBrightness:
     * 控制动画（呼吸灯）每一步变化的亮度最小值，驱动里面做了动态调整。
     */
    public int configLed(int level, int maxBrightness, int minBrightness, int stepBrightness) {
        Log.d(TAG, "configLed:level=" + level
                + ",maxBrightness=" + maxBrightness
                + ",stepBrightness=" + stepBrightness);
        try {
            return mService.configLed(level, maxBrightness, minBrightness, stepBrightness);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in configLed", e);
            return -1;
        }
    }

    /*
     * single led control for Red
     * @param on
     */
    public void setSingleLedRGBRedOn(boolean on) {
        try {
            mService.setSingleLedRGBRedOn(on);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in startAnimation", e);
        }
    }

    /*
     * single led control for Green
     * @param on
     */
    public void setSingleLedRGBGreenOn(boolean on) {
        try {
            mService.setSingleLedRGBGreenOn(on);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in startAnimation", e);
        }
    }

    /*
     * single led control for Blue
     * @param on
     */
    public void setSingleLedRGBBlueOn(boolean on) {
        try {
            mService.setSingleLedRGBBlueOn(on);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in startAnimation", e);
        }
    }

    /*
     * single led control for Power led (tail led)
     * @param on
     */
    public void setSingleLedPowerOn(boolean on) {
        try {
            mService.setSingleLedPowerOn(on);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in startAnimation", e);
        }
    }

    /*
     * get state (on or off) of Single Red led
     * @return true: on; false: off
     */
    public boolean getSingleLedRGBRedOn() {
        try {
            return mService.getSingleLedRGBRedOn();
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in startAnimation", e);
        }

        return false;
    }

    /*
     * get state (on or off) of Single Green led
     * @return true: on; false: off
     */
    public boolean getSingleLedRGBGreenOn() {
        try {
            return mService.getSingleLedRGBGreenOn();
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in startAnimation", e);
        }

        return false;
    }

    /*
     * get state (on or off) of Single Blue led
     * @return true: on; false: off
     */
    public boolean getSingleLedRGBBlueOn() {
        try {
            return mService.getSingleLedRGBBlueOn();
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in startAnimation", e);
        }

        return false;
    }

    /*
     * get state (on or off) of Single Power led
     * @return true: on; false: off
     */
    public boolean getSingleLedPowerOn() {
        try {
            return mService.getSingleLedPowerOn();
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in startAnimation", e);
        }

        return false;
    }

}
